<?xml version="1.0" encoding="UTF-8"?>

<Module>
 <ModulePrefs title="Reply Using Twitter"
              author="Cisco"
              author_email="help@cisco.com"
              scrolling="true"
              height="700">
   <Require feature="dynamic-height"/>
   <Require feature="settitle"/>
   <Require feature="minimessage"/>
   <Require feature="setprefs"/>
   <Locale messages="http://10.68.37.114/templates/reply/../../messages/en_US.xml"/>
 </ModulePrefs>
 <Content type="html">
   <![CDATA[
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

<style type="text/css">

body {
	font-family:"Lucida Grande",Verdana,sans-serif;color:#000000;
	font-size:12px;
	position:absolute;z-index:0;top:0px;left:0px;
	background-color:transparent; 
	width:100%;
	margin:0;padding:0;border:0;
}
	  
a:link             {color:#333399;text-decoration:underline;} 
a:visited          {color:#993366;text-decoration:underline;} 
br                 {line-height:8px;clear:both;}


th {
background-color:#eef3f8;
border-bottom:1px solid #eef3f8;
border-top:1px solid #eef3f8;
border-left:1px solid #eef3f8;
border-right:1px solid #FFFFFF;
font-weight:normal;
line-height:16px;
padding-left:2px;
padding-right: 2px;
text-align:left;
vertical-align:middle;
}

td {
line-height:16px;
padding: 1px;
vertical-align: top;
}

td input[type="checkbox"] {
	margin-left: 6px;
}

.transferBox {
	margin-top: 15px;
	width: 480px;
}

.transferBox select {
	height: 200px;
	width: 200px;
}

.transferBox div {
	float: left;
	margin-left: 2px;
	margin-right: 2px;
}

.transferBox .controls {
	width: 40px;
	padding-top: 30px;
}

.transferBox .controls .spacer {
	display: block;
	height: 25px;
}

.transferBox div button {
	width: 100%;
	margin-left: 0 auto ;
	margin-right: 0 auto ;
}

.layer {
	clear: both;
}

button {
         cursor:pointer;
}

legend {
    font-size:14px;
    font-weight:bold;
    position:relative;
    top:-.4em;
}

select:disabled{
	background-color:#DCDCDC;
}

div.floatLeft {
	float: left;
	margin: 5px 0 0 10px;
	width: 500px;
}

.layerHeadingFloat {
	float: left;
	margin: 0;
	padding: 0 0 5px 0;
}

.toolbar {
	float: right;
	margin-right: 5px;
}

.toolbar IMG {
	border:0;
	width: 20px;
	height: 20px;
	padding-left: 3px;
	padding-top: 1px;
	cursor: pointer;
}

.hidden {
	display: none;
}

div.floatRight {
	float: right;
	margin: 7px 50px 0 0;
}

span.floatLeft {
	float: left;
	margin: 10px 0 0 10px;
}

span.floatRight {
	float: right;
	margin: 7px 50px 0 0;
}

.title {
	border-top: thin outset #407bb3;
	font-weight:normal;
	line-height:16px;
	text-align:left;
	vertical-align:middle;
	display: inline-block;
	width: 100%;
	height: 22px;
	padding-top: 1px;
}

.layerHeading {
	font-size:16px;
	font-weight:normal;
}

.info, .success, .warning, .error, .systemError, .systemWarning{
	width: 100%;
    border: 1px solid;
	margin: 5px 0px;
	padding:5px;
    background-repeat: no-repeat;
    background-position: 10px center;
}
.info {
	border-color: #00529B;
    background-color: #BDE5F8;
}
.success {
    border-color: #4F8A10;
    background-color: #DFF2BF;
}
.warning {
    border-color: #9F6000;
    background-color: #FEEFB3;
}
.systemWarning {
    border-color: #9F6000;
    background-color: #FEEFB3;
}
.error {
    border-color: #D8000C;
    background-color: #FFBABA;
}

.systemError {
    border-color: #D8000C;
    background-color: #FFBABA;
}

.settingsLabel {
	font-weight:bold;
}


textarea.errorHighlight{background-color:red}

#summaryData {
        
		overflow-x:hidden;
		padding: 2px;
}

#detailsForm {
		overflow-x:hidden;
		padding: 2px;
}

.content {
	overflow-y:auto;
	height: 500px;
}

.gadgetHeader {
	overflow-y:hidden;
	padding-bottom: 5px;
}

.footer {
	padding-top: 10px;
}

#postList {
		overflow-x:hidden;
		overflow-y:hidden;
		padding: 0px 2px 2px 2px;	
}

input.error {
	border: 1px solid red;
}

.postEntry:hover .statecontrols {
	/* opacity: 1.0; */
}

.statecontrols {
	display: inline-block;
	float: right;
    border:0;
    margin-right:0px;
    margin-left: auto;
	margin-top: 2px;
	margin-bottom: 2px;
	/* opacity: 0.01; */
}

.statecontrols IMG {
    border:0;
    width:18px;
    height:18px;
    margin-right:0px;
    padding: 0px 5px 0px 5px;
    cursor: pointer;
}

IMG.feedStatusIcon {
	border:0;
	width:16px;
	height:16px;
	margin-right:0px;
	padding: 0px 2px 0px 1px;
}

IMG.serverStatusIcon {
	border:0;
	width:16px;
	height:16px;
	margin-right:0px;
	padding: 0px 0px 0px 1px;
	vertical-align:bottom;
}

.throughputGradient {
	border:0;
	width:130px;
	height:30px;
	vertical-align:middle;
	display:inline-block;
}

.throughputGraph {
	width:130px;
	height:30px;
	position:relative;
	right:133px;
	vertical-align:middle;
	display:inline-block;
}

.contactstate {
    float:right;
	vertical-align: middle;
	height: 22px;
	display: inline;
	margin: 2px 2px 2px 2px;
}

.updated, .author {
	float: left;
	vertical-align: middle;
	display: inline;
	font-size:10px;
	color: #222222;
}

.trainingResponse, .tagResponse {
	text-align: center ;
	padding: 1px 5px;
	border: 1px solid;
	border-color: #4F8A10;
	background-color: #DFF2BF;
	margin: 2px 2px 2px 2px;
	float: left;
}

.tagResponse {
	margin-left: 5px;
}

.verticalSeparator {
	display: inline-block;
	border-left: 2px solid;
	border-color: #8499A2;
	height:18px;
}

.trainingHeading {
	
	padding-right: 40px;
}

.tags {
	clear: both;
	margin-top: 5px;
	width: 100%;
}

.proxy {
	margin-top: 5px;
	width: 380px;
}

.tags input[type="text"] 
{
  width: 100px;
}

.proxy label 
{
  display: inline-block;
  float: left;
  min-width: 10em;
  text-align: left;
  margin: 4px;
}

.proxyExcludeList
{ 
  height:250px;
  overflow:auto;
 }

/*
   Set proxy settings link style so it looks the same
   even after it is clicked
*/
.proxySettingsLink
{ 
  float: right;
  margin-bottom: 5px;
  margin-right: 10px;
 }

a.proxySettingsLink:link, a.proxySettingsLink:visited
{ 
  color:#333399;
  text-decoration:underline;
 }

.proxy input[type="text"]
{ 
  margin: 3px;
  width: 200px;
 } 

.proxy input[type="checkbox"]
{ 
  margin: 3px;
 }

.proxySettings:disabled
{ 
  background-color:#DCDCDC;
 }

.postEntry:hover input[type="text"]
{
	border: 1px solid;
	border-color: #407BB3;
	
}

.postEntry input[type="text"] {
	border: 1px solid;
	border-color: #407BB3;
}

.postEntry button {

}

.postEntry:hover {
	background-color: #EEF3F8;
	width: 100%;
}

.postEntry a, .postEntry a:link, .postEntry a:visited {
	color:#333399;
	text-decoration: none;
	font-size: 13px;
}

.postEntry a:hover {
	text-decoration: underline;
}

.postEntry {
	width: 100%;
	padding-bottom: 5px;
}

.suggestedTagsWrapper {
	
	height: 20px;
}

.suggestedTags
{	
}

.tagSuggestion {
	color:#555599;
	text-decoration: none;
}


.tagSuggestion:hover {
	text-decoration: underline;
	cursor: pointer;
}

.postEntry:hover .suggestedTags {
}

.currentTags {
}

.postEntry:hover .addTags {
  visibility: inherit;
/*	opacity: 1.0;
	-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=100)";*/
}

.postEntry .addTags {
  visibility: hidden;
/*	opacity: 0.01;
	-ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";*/
}

.summary {
	width: 100%;
	margin-bottom: 2px;
}
.tag,.proxyExcludeTag {
	display: inline-block;
	border-color: #AEB8BC;
	background:none repeat scroll 0 0 #DFF4FF;
	border:1px solid #A7CEDF;
	
	margin-bottom: 3px;
	margin-right: 3px;
	padding:2px 3px 2px 3px;
	
	-moz-border-radius: 5px;
	-webkit-border-radius: 5px;
	-khtml-border-radius: 5px;
}

#pendingResultsContainer {
	height: 20px;
	width: 100%;
	display: inline-block;
	margin-top: 2px;
	padding-bottom: 5px;
}

#pendingResults {
	display: inline-block;
	border-color: #AEB8BC;
	background:none repeat scroll 0 0 #DFF4FF;
	width: 100%;
	text-align: center;
	line-height: 20px;	
	cursor: pointer;
	-moz-border-radius: 5px;
	-webkit-border-radius: 5px;
	-khtml-border-radius: 5px;
}

#pendingResults:hover {
	text-decoration: underline;		
}

.proxyExcludeTag
{
  display: block;
  min-width: 15em;
  }
img.deleteTag,img.deleteProxyExcludeTag {
	width: 8px;
	height: 8px;
	margin-left: 3px;
	cursor: pointer;
}

img.deleteProxyExcludeTag 
{
  float:right;
  vertical-align: center;
  margin: 3px;
}

td.rb {
	text-align: right;
    vertical-align: bottom;
}

#loadingIndicatorMessage {
	display: inline-block;
	margin-left: 10px;
	vertical-align: super;
	color:#407BB3;
	font-size:14px;
}

#loadingIndicator {
	border:2px solid #ccc;
	margin: 10px;
	padding: 10px;
	width: 100px;
	background-color: white;
	
	
	
	-moz-border-radius: 20px;
    -webkit-border-radius:20px;
    -khtml-border-radius:20px;
    -moz-box-shadow: 0 1px 5px #333;
    -webkit-box-shadow: 0 1px 5px #333;
}

#loadingIndicator IMG {
	height: 30px;
	width: 30px;
	background: transparent;
}

.signinOverlay, #loadingOverlay {
    position:fixed;
    top:0px;
    bottom:0px;
    left:0px;
    right:0px;
    z-index:100;
}

.signinOverlay {
	background: url(../img/overlay.png) repeat top left;
}

.signinBox{
    position:fixed;
    top:-325px;
    left:30%;
    right:30%;
    background-color:#fff;
    color:#7F7F7F;
    padding:20px;
    border:2px solid #ccc;
    -moz-border-radius: 20px;
    -webkit-border-radius:20px;
    -khtml-border-radius:20px;
    -moz-box-shadow: 0 1px 5px #333;
    -webkit-box-shadow: 0 1px 5px #333;
    z-index:101;
}

.signinBox h1
{
    border-bottom: 1px dashed #7F7F7F;
    margin:-20px -20px 0px -20px;
    padding:10px;
    background-color:#eef3f8;
    color:#407BB3;
    -moz-border-radius:20px 20px 0px 0px;
    -webkit-border-top-left-radius: 20px;
    -webkit-border-top-right-radius: 20px;
    -khtml-border-top-left-radius: 20px;
    -khtml-border-top-right-radius: 20px;
}

.signinBox input[type="text"], .signinBox input[type="password"] {
	width: 155px;
}
  
/*
admin settings
*/  
  .adminSettings input[type="text"]
{ 
  margin: 1px;
  width: 300px;
 }
 
  .adminSettings input[type="password"]
{ 
  margin: 1px;
  width: 300px;
 }
 
   .adminSettings input[type="checkbox"]
{ 
  margin: 1px; 
 }
 
.inputRow {
	clear: both;
	height: 28px;
}

.inputRow label {
	display: inline-block;
	float: left;
	min-width: 16em;
	text-align: left-center;
	margin: 1px;
	vertical-align: middle;
}

.inputRow input[type="text"] {
	margin: 1px;
}
 
 .adminSettings label 
{
  display: inline-block;
  float: left;
  min-width: 16em;
  height: 28px;
  text-align: left-center;
  margin: 1px;
}

  .adminSettings span
{
	float: left;
	width: 350px;
	word-wrap: break-word; 
}

#purgeSettings label {
	min-width: 24em;
}

#reportingUserSettings label {
	min-width: 14em;
}

#purgeSettings input[type="text"] {
	width: 60px;
}

.server_status {
	margin: 20px 0;
	float: left;
}

ul {
	margin: 0px;
	padding-left: 14px;
}

.server_status label{
	display:block;
	width:100%;	
}

.server_status ul {
	margin-top: 5px;
	width: 150px;
	float:left;
}

.server_status ul li {
	height: 20px;
}

.server_status ul li label {
	display: inline-block;
	width: 65px;
}

ul.notification_status li label{
	width:45px;
}

.system_stats{
	clear:both;
	margin-top:20px;	
}

.drawer_title {
	clear: both;
	margin-top: 10px;
}

.drawer_title IMG {
	width: 10px;
	height: 10px;
	cursor: pointer;
}

div.drawer {
	float: left;
	margin: 10px 0 5px 14px;
	padding-bottom: 10px;
	width: 550px;
	border-bottom: thin solid #407BB3;
}

.heading 
{
	color:#407BB3;
	font-size:14px;
}

.heading:hover 
{
	color:#407BB3;
	text-decoration: underline;
	cursor: pointer;
}

.campaignResultsSettingsLayer
{
	float: left;
	margin-left: 5px;
	width: 99%;
}

.campaignResultsBoxes
{
	width:400px;
	height:110px;
}

.campaignResultsSettingsHeader {
	font-size:14px;
	font-weight:bold;
	display: block;
	margin-top:15px;
    margin-bottom:5px;	
}

.firstHeader {
	margin-top: 0px;
}

.campaignResultsCheckBox {
	margin: 0px;
	margin-bottom:4px;
	
}

.example {
	color:#888888;
	font-size:10px;
	vertical-align: middle;
}

#sampleCodeDrawerContents {
	border: 1px solid #7F7F7F;
	border: thin solid #407BB3;
	margin-top: 10px;
	margin-left: 15px;
	margin-right: 15px;
}

#sampleCodeDisplayHeader {
	background-color: #eef3f8;
	font-size: 14px;
	padding: 3px;
}

#sampleCodeDisplayContent {
	padding: 3px;
}

ul.topnav {
	list-style: none;
	padding: 0;
	margin: 0;
	float: left;
	z-index: 10;
}
ul.topnav li {
	cursor: pointer;
	float: left;
	margin: 0;
	padding: 1px 5px 1px 5px;
	position: relative; /*--Declare X and Y axis base for sub navigation--*/
	font-size: 1.2em;
	max-width:450px;
	border: 1px solid #EEF3F8;
	-webkit-border-radius: 5px;
	-moz-border-radius: 5px;
	border-radius: 5px;
}
ul.topnav li:hover{
	border: 1px solid #407BB3;
}
ul.topnav li span.menuTitle {
	float: left;
	overflow-x: hidden;
	white-space: nowrap;
	max-width: 430px;
}
ul.topnav li span.arrow { /*--Drop down trigger styles--*/
	width: 12px;
	height: 24px;
	float: right;
	background: url(../img/drawerTriangleOpen.png) no-repeat center center;
}
ul.topnav li ul.subnav {
	font-size: 14px;
	list-style: none;
	position: absolute;
	left: 0; top: 28px;
	background: #fff;
	margin: 0; padding: 0;
	display: none;
	float: left;
	border: 1px solid #407BB3;
	max-height: 500px;
	max-width: 650px;
	-webkit-border-radius: 5px;
	-webkit-border-top-left-radius: 0;
	-moz-border-radius: 5px;
	-moz-border-radius-topleft: 0;
	border-radius: 5px;
	border-top-left-radius: 0;
	overflow-x: hidden;
	overflow-y: auto;
	text-overflow: ellipsis;
	white-space: nowrap;
}
ul.topnav li ul.subnav li:first-child{
	border: none;
}
ul.topnav li ul.subnav li{
	margin: 0; padding: 0;
	border: none;
	border-radius: 0;
	-webkit-border-radius: 0;
	-moz-border-radius: 0;
	border-top: 1px solid #407BB3;
	clear: both;
	cursor: pointer;
	width:100%;
	max-width:650px;
}
ul.topnav li ul.subnav li:hover{
	background: #EEF3F8;
}
html ul.topnav li ul.subnav li span {
	float: left;
	padding-left: 5px;
	background: none;
}


.notificationRow {
	clear: both;
	height: 28px;
}

.notificationRow label {
	display: inline-block;
	float: left;
	min-width: 10em;
	text-align: left-center;
	margin: 1px;
	vertical-align: middle;
	margin-left: 1em; 
}

.notificationRow input[type="text"] {
	margin: 1px;
	width: 50%;
}

.notificationRow select {
	margin: 1px;
	width: 51%;
}

.notificationRow textarea {
	margin: 1px;
	width: 60%;
}

.addressList
{ 
  margin-left: 10em;
  overflow:auto;
  width: 52%;
 }
 
 /* DataTable styles */

table.display {
	clear: both;
	margin-top: 5px;
	margin-bottom: 5px;
	width: 100%;
	border-bottom: 1px solid #CCCCCC;
	border-top: 1px solid #CCCCCC;
}

table.display thead th {
	padding: 3px 5px 3px 5px;
	background-color: white; /* #D9E5F0; - TODO - change to this color once the sorting arrows have a new color */
	font-weight: bold;
	border-bottom: 1px solid #CCCCCC;
	border-top-style: none;
}

table.display td {
	padding: 4px;
}

table.display td.center {
	text-align: center;
}

tr.even {
	background-color: #EFF3F6;
}

.sorting, .sorting_asc, .sorting_desc { 
	cursor: pointer;
}

.sorting_asc {
	background: url('../img/sort_asc.png') no-repeat center right;
}

.sorting_desc {
	background: url('../img/sort_desc.png') no-repeat center right;
}

.sorting {
	background: url('../img/sort_both.png') no-repeat center right;
}

.dataTables_filter {
	float: left;
	font-size: 10px;
}

.dataTables_info {
	float: right;
	font-size: 10px;
	line-height: 22px;
}



.profileName
{
    display: inline-block;
    font-weight: bold;
    font-size: 14px;
    height: 22px;
    line-height: 16px;
    padding-top: 0px;
    padding-bottom: 5px;
    text-align: left;
    vertical-align: middle;
    width: 100%;
}

.profilePicture
{
    float: left;
    padding-bottom: 2px;
}

.profile
{
    margin-left: 58px;
}

.profileText
{
    display: inline-block;
    font-size: 12px;
    line-height: 16px;
    text-align: left;
    vertical-align: middle;
    padding-bottom: 4px;
    width: 100%;
}

.profileUrl
{
    display: inline-block;
    font-size: 12px;
    line-height: 16px;
    text-align: left;
    vertical-align: middle;
    padding-bottom: 4px;
    width: 100%;
}

.profileUrl:hover
{
    display: inline-block;
    font-size: 12px;
    line-height: 16px;
    text-align: left;
    vertical-align: middle;
    padding-bottom: 4px;
    width: 100%;
    cursor: pointer;
    text-decoration: underline;
}

.conversation
{
    float: left;
    height: 350px;
    overflow: auto;
    padding-top: 10px;
    width: 100%;
}

.author
{
    border-top: thin outset #407BB3;
    display: inline-block;
    font-weight: bold;
    font-size: 14px;
    height: 22px;
    line-height: 16px;
    padding-top: 1px;
    text-align: left;
    vertical-align: middle;
    width: 100%;
}

.repliedToTweet
{
    bottom: 0;
    padding-left: 5px;
    padding-right: 5px;
    width: 480px;
}

.retweetedTweet
{
    padding-left: 5px;
    padding-right: 5px;
    width: 490px;
    background: white;
}

.authorSmall
{
    display: inline-block;
    font-weight: bold;
    font-size: 12px;
    height: 20px;
    line-height: 14px;
    padding-top: 1px;
    text-align: left;
    vertical-align: bottom;
    width: 100%;
}

.descriptionSmall
{
    display: inline-block;
    font-weight: normal;
    font-size: 12px;
    line-height: 14px;
    padding-top: 1px;
    padding-bottom: 5px;
    text-align: left;
    vertical-align: bottom;
    width: 100%;
}

.draggableDialog
{
    visibility: hidden;
    background-color: #407BB3;
    outline-color:  #407BB3;
    outline-style: solid;
    outline-width: thick;
    position: absolute;
    top: 50px;
    left: 10px;
    width: auto;
    height: auto;
}

.draggableDialogHeader
{
    position:absolute;
    top:0px;
    left:0px;
    width:100%;
    height:25px;
    cursor:move;
    background-color:#EEF3F8;
    font-weight:bold;
}

.innerDialog
{
    position:relative;
    margin:25px 0px 0px 0px;
    outline-color:#EEF3F8;
    outline-style:thick;
    background-color:white;
    width:100%;
    height:auto;
}

.closeDialog
{
    cursor:pointer;
    position:absolute;
    top:2px;
    right:5px;
    font:bold 16px/18px Tahoma,sans-serif;
    color:#000000;
}

.tweetArea
{
    font-family:Arial;
    font-size:12px;
    line-height:16px;
    padding-left:8px;
    padding-top:2px;
    vertical-align:middle;
    margin:5px 5px 5px 5px;
    width:480px;
    height:100px;
}

.dialogButtons
{
    display: block;
    padding: 10px 0 10px 0;
    text-align: right;
    width: 480px;
}

.sendButton
{
    right:5px;
}

.tweetButton
{
    padding-right: 5px;
    padding-left: 5px;    
}

.countDown
{
    text-align: right;
    padding-right: 5px;
    padding-left: 5px;
}

.actionGroup
{
    padding-top:8px;
    padding-bottom:8px;
}

.replyAction
{
    cursor:pointer;
    padding-left:4px;
    padding-right:4px;
    color:#407BB3;
}

.replyAction:hover
{
    cursor:pointer;
    padding-left:4px;
    padding-right:4px;
    color:#407BB3;
    text-decoration:underline;
}

.progressLayer
{
    position: absolute;
    top: 0;
    left: 0;
    opacity: 0.5;
    visibility: hidden;
    background-color: #EEF3F8;
    z-axis: 1;
}

.progressMessage
{
    position: absolute;
    background-color: white;
    border-style: solid;
    border-width: medium;
    border-radius: 5px;
    -moz-border-radius: 5px;
    z-axis: 2;
    opacity: 1.0;
}

.progressSpan
{
    font-size: 18px;
    font-weight: bold;
    padding: 5px 5px 5px 5px;
}

</style>

<script type="text/javascript">


//
// The following code manages the dialog used to reply, retweet, and message
//

/**
 * Keep track of the currently selected dialog
 */
var currentDialog = null ;

/**
 * Class used to store information about a given dialog
 */
function DraggableDialog(grabbableClassName, dialogId)
{
    this.grabbableClassName = grabbableClassName ;
    this.dialog = document.getElementById(dialogId) ;

    this.offsetX = 0 ;
    this.offsetY = 0 ;
    this.dragging = false ;
}

/**
 * Set the currently displayed dialog
 */
function setDraggableDialog(grabbableClassName, dialogId)
{
    if ( currentDialog != null )
    {
        return ;
    }
    
    currentDialog = new DraggableDialog(grabbableClassName, dialogId) ;

    document.onmousedown = onMouseDown ;
    document.onmouseup   = onMouseUp ;
    document.onmousemove = onMouseMove ;
}

/**
 * Handle mouse down events.This consists of determining whether or not the
 * grabbable part of the dialog was clicked.
 */
function onMouseDown(event)
{
    if ( currentDialog == null )
    {
        return ;
    }

    if ( (event == null) || (event == undefined) )
    {
        event = window.event ;
    }

    var target = event.target || event.srcElement ;
        
    if ( target.className == currentDialog.grabbableClassName )
    {
        currentDialog.offsetX = event.clientX - currentDialog.dialog.offsetLeft ;
        currentDialog.offsetY = event.clientY - currentDialog.dialog.offsetTop ;

        currentDialog.dragging = true ;
    }
}

/**
 * Handle mouse up. Stop dragging the dialog.
 */
function onMouseUp(event)
{
    if ( currentDialog == null )
    {
        return ;
    }

    currentDialog.dragging = false ;
}

/**
 * Redraw the dialog if th user is dragging it
 */
function onMouseMove(event)
{
    if ( currentDialog == null )
    {
        return ;
    }

    if ( (event == null) || (event == undefined) )
    {
        event = window.event ;
    }
    
    if ( currentDialog.dragging )
    {
        currentDialog.dialog.style.left = (event.clientX - currentDialog.offsetX) + "px" ;
        currentDialog.dialog.style.top  = (event.clientY - currentDialog.offsetY) + "px" ;
    }
}

/**
 * Open/display the currently selected dialog
 */
function openDialog()
{
    if ( currentDialog == null )
    {
        return ;
    }

    currentDialog.dialog.style.visibility = "visible" ;
}

/**
 * Close/hide the currently selected dialog
 */
function closeDialog()
{
    if ( currentDialog == null )
    {
        return ;
    }

    currentDialog.dialog.style.visibility = "hidden" ;
    
    currentDialog = null ;
}
   

/**
 * Parameter name of the social contact's reference URL.  The value of
 * this parameter is used to derive the other REST paths used in the
 * reply template.
 */
var SC_REF_URL_PARAM = "scRefUrl" ;

/**
 * Parameter that stores the origin of the campaign results gadget.
 */
var ORIGIN_PARAM = "origin" ;

/**
 * CCP Feed API path
 */
var CCP_FEED_REST_PATH    = "/ccp-webapp/ccp/feed" ;

/**
 * CCP Twitter status update API path 
 */
var STATUS_MESSAGE_PATH   = "/ccp-webapp/ccp/reply/twitter/statuses/update" ;

/**
 * CCP Twitter retweet API path 
 */
var STATUS_RETWEET_PATH   = "/ccp-webapp/ccp/reply/twitter/statuses/retweet" ;

/**
 * CCP Twitter direct message API path
 */
var DIRECT_MESSAGE_PATH   = "/ccp-webapp/ccp/reply/twitter/direct_messages/new" ;

/**
 * CCP Twitter friendships/exists API path
 */
var FRIENDSHIPS_EXISTS_PATH = "/ccp-webapp/ccp/reply/twitter/friendships/exists" ;

/**
 * CCP Twitter follow API path
 */
var FOLLOW_PATH = "/ccp-webapp/ccp/reply/twitter/follow" ;

/**
 * CCP Twitter unfollow API path
 */
var UNFOLLOW_PATH = "/ccp-webapp/ccp/reply/twitter/unfollow" ;

/**
 * CCP Twitter users show API path
 */
var USERS_SHOW_PATH = "/ccp-webapp/ccp/reply/twitter/users/show" ;

/**
 * CCP API to retrieve a conversation ending with the given contact
 */
var CONVERSATION_PATH = "/ccp-webapp/ccp/conversation" ;
/**
 * Social contact handled state
 */
var SC_STATUS_HANDLED = "handled" ;
	
/**
 * Social contact reserved state
 */
var SC_STATUS_RESERVED = "reserved" ;

var TWITTER_PROGRESS_SUCCEEDED	 = "SUCCEEDED";
var TWITTER_PROGRESS_FAILED		 = "FAILED";
var TWITTER_PROGRESS_IN_PROGRESS = "IN-PROGRESS";

var PROGRESS_TAG          = "progress" ;
var HTTP_RESPONSE_MSG_TAG = "httpResponseMessage" ;
var RATE_LIMITED_TAG      = "rateLimited" ;

//
// Utility Functions
//

/**
 * Determine if the given string is undefined, null, or is empty
 */
function isEmptyString(string)
{
    if ( (string == undefined) || (string == null) || (string == "") )
    {
        return true ;
    }
    
    return false ;
}

/**
 * Found the parameter with the given name in the URL used to retrieve this
 * page.
 */
function getRequestParameterValue(paramName, url)
{
	paramName = paramName.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]") ;
	var regexS = "[\\?&]" + paramName + "=([^&#]*)" ;
	var regex = new RegExp(regexS) ;
	var results = regex.exec(url) ;
	if( results == null )
	{
	 	return "" ;
	}

	return results[1] ;
}

/**
 * Retrieve the node with the given name from the xml contained in the xml
 * parameter
 */
function getElementValue(xml, nodeName)
{
    if ( xml == undefined )
    {
        log("xml is undefined for " + nodeName) ;
    }
    
	var element = xml.getElementsByTagName(nodeName) ;
	if ( (element == null) ||
	     (element[0] == null) ||
	     (element[0].childNodes[0] == null) )
	{
		return "" ;
	}
	
	return element[0].childNodes[0].nodeValue ;
}

/**
 * Log to Firebug if it is present
 */
function log(msg)
{
	if( typeof console === "undefined" )
	{
	    return ;
	}
	
	console.log(msg) ;
}

//
// Twitter Message class definition
//

/**
 * Class used to manage calls to the Twitter reply API. This class will make the
 * REST request and then poll until the operation completes.
 */
function TwitterMessage(ccpSession, url, method, callback, postData)
{
	this.ccpSession = ccpSession ;
	
	this.method   = method ;
	this.url      = url ;
	
	this.callback = callback ;
	this.postData = postData ;
	
	this.intervalId = null ;
	
	this.statusUrl = null ;
}

/**
 * Stop polling for progress
 */
TwitterMessage.prototype.stopPolling = function()
{
	if ( this.intervalId == null )
	{
		return ;
	}

	clearInterval(this.intervalId) ;
	
	log("interval[" + this.intervalId + "] clear") ;

	this.intervalId = null ;
	this.statusUrl = null ;
}

/**
 * Check the progress of the operation
 */
TwitterMessage.prototype.checkProgress = function()
{
	var self = this ;
	
	var progressCallback = function(obj)
	{
		if ( obj.rc != 200 )
		{
			self.stopPolling() ;
			self.callback(obj, self) ;
			
			return ;
		}

		var progress = getElementValue(obj.data, PROGRESS_TAG) ;
		if ( (progress == TWITTER_PROGRESS_SUCCEEDED) ||
			 (progress == TWITTER_PROGRESS_FAILED) )
		{
			self.stopPolling() ;
			self.callback(obj, self) ;
		}
		
		// If progress == IN_PROGRESS, let the interval continue to poll
		// for status.
		//
	}
	
	this.ccpSession.makeRequest(this.statusUrl, gadgets.io.MethodType.GET, progressCallback) ;
}

/**
 * Send the initial request
 */
TwitterMessage.prototype.send = function()
{
	var self = this ;
	
	var initialCallback = function(obj)
	{
		if ( obj.rc != 202 )
		{
			self.callback(obj, self) ;
			
			return ;
		}
		
		self.statusUrl = obj.headers.location[0] ;
		
		function progressInterval()
		{
			self.checkProgress() ;
		}
		self.intervalId = setInterval(progressInterval, 1000) ;
		log("interval[" + self.intervalId + "] set") ;
	}
	this.ccpSession.makeRequest(self.url, self.method, initialCallback, self.postData) ;
}


//
// CcpSession class definition
//

/**
 * The CcpSession class allows applications to interact with CCP as follows:
 *   - get the details of the social contact
 *   - change the state of the social contact
 *   - get the list of Twitter accounts available on CCP.  These accounts can
 *     be used to send Twitter messages
 *   - send Twitter status updates and direct messages
 * 
 * The href parameter is the URL of the reply template.  It is expected to
 * have an scRefUrl parameter in it.  This parameter is used to find the
 * protocol, port, and server to use to communicate with CCP.  
 */
function CcpSession(href)
{
	this.restSocialContact = unescape(getRequestParameterValue(SC_REF_URL_PARAM, unescape(href))) ;
	
	var ccpProtocol = "" ;
	var ccpHost = "" ;
	var ccpPort = "" ;
	
	// The following regex parses the protocol, host, and port from the social
	// contact's refUrl.  This gives the page a path back to CCP's REST APIs.
	//
	e = /([^:]+):\/\/([^:/]+):*([0-9]*)/ ;
	var array = this.restSocialContact.match(e) ;
	if ( array != null )
	{
		ccpProtocol = array[1] ;
		ccpHost = array[2] ;
		ccpPort = array[3] ;
	}
	
	var ccpBasePath = ccpProtocol + "://" + ccpHost + (ccpPort == "" ? "" : ":" + ccpPort) ;
	
	this.restGetFeedList       = ccpBasePath + CCP_FEED_REST_PATH ;	
	this.restSendStatusMessage = ccpBasePath + STATUS_MESSAGE_PATH ;
    this.restRetweetMessage    = ccpBasePath + STATUS_RETWEET_PATH ;
	this.restSendDirectMessage = ccpBasePath + DIRECT_MESSAGE_PATH ;
	this.restFriendshipsExists = ccpBasePath + FRIENDSHIPS_EXISTS_PATH ;
	this.restFollow            = ccpBasePath + FOLLOW_PATH ;
    this.restUnfollow          = ccpBasePath + UNFOLLOW_PATH ;
	this.restUsersShow         = ccpBasePath + USERS_SHOW_PATH ;
	this.restGetConversation   = ccpBasePath + CONVERSATION_PATH ;
	
	this.prefs = new gadgets.Prefs() ;
	
	// Location of the campaign-results gadget.  This attribute is necessary
	// to post messages to the campaign results gadget.
	//
	this.origin = this.prefs.getString("origin") ;
	
	// Authorization string used to make REST requests to CCP.
	//
	this.authString = this.prefs.getString("CCPAuthString") ;

	// Message used for following and friendship requests
	this.currentFollow = null ;
	
	// Message used for direct messages and tweets
	this.currentMessage = null ;
}

/**
 * Get the social contact's details.
 */
CcpSession.prototype.getSocialContact = function(callback)
{
	this.makeRequest(this.restSocialContact, gadgets.io.MethodType.GET, callback) ;
}

/**
 * Get the list of feeds configured on CCP.
 */
CcpSession.prototype.getAllCcpFeeds = function(callback)
{
	this.makeRequest(this.restGetFeedList, gadgets.io.MethodType.GET, callback) ;
}

/**
 * Manage handling of messages to Twitter via CCP.  This method allows one
 * follow-related message at a time.
 */
CcpSession.prototype.processFollow = function(url, method, callback, postData)
{
	if ( this.currentFollow != null )
	{
		log("currentFollow: " + this.currentFollow.url + " is already set") ;
		return ;
	}
	
	var self = this ;
	var wrapCallback = function(obj, message)
	{
		log("currentFollow: " + self.currentFollow.url + " cleared") ;
		self.currentFollow = null ;
		callback(obj) ;
	}
	this.currentFollow = new TwitterMessage(this, url, method, wrapCallback, postData) ;
	log("currentFollow: " + self.currentFollow.url + " set") ;
	this.currentFollow.send() ;
}

/**
 * Manage handling of messages to Twitter via CCP.
 */
CcpSession.prototype.processMessage = function(url, method, callback, postData)
{
	if ( this.currentMessage != null )
	{
		log("currentMessage: " + this.currentMessage.url + " is already set") ;
		return ;
	}
	
	var self = this ;
	var wrapCallback = function(obj, message)
	{
		log("currentMessage: " + self.currentMessage.url + " cleared") ;
		self.currentMessage = null ;
		callback(obj) ;
	}
	this.currentMessage = new TwitterMessage(this, url, method, wrapCallback, postData) ;
	log("currentMessage: " + self.currentMessage.url + " set") ;
	this.currentMessage.send() ;
}

/**
 * Send a status message using the Twitter account with the given username.
 */
CcpSession.prototype.twitterStatusUpdate = function(username, message, callback)
{
	var postData =
			"<Status>\n" +
			"  <username>" + username + "</username>\n" +
			"  <message>" + message + "</message>\n" +
			"</Status>" ;

	this.processMessage(this.restSendStatusMessage, gadgets.io.MethodType.POST, callback, postData) ;
}

/**
 * Send a status message using the Twitter account with the given username.
 */
CcpSession.prototype.twitterReply = function(username, message, statusId, callback)
{
	var postData =
			"<Status>\n" +
			"  <username>" + username + "</username>\n" +
			"  <message>" + message + "</message>\n" +
			"  <inReplyToStatusId>" + statusId + "</inReplyToStatusId>\n" +
			"</Status>" ;

	this.processMessage(this.restSendStatusMessage, gadgets.io.MethodType.POST, callback, postData) ;
}

/**
 * Send a direct message using the account specified by fromUsername to the user
 * specified in toUsername.
 */
CcpSession.prototype.twitterDirectMessage = function(fromUsername, toUsername, message, callback)
{
	var postData =
		"<DirectMessage>\n" +
		"  <fromUsername>" + fromUsername + "</fromUsername>\n" +
		"  <toUsername>" + toUsername + "</toUsername>\n" +
		"  <message>" + message + "</message>\n" +
		"</DirectMessage>" ;

	this.processMessage(this.restSendDirectMessage, gadgets.io.MethodType.POST, callback, postData) ;
}

/**
 * Retweet the specified tweet.
 */
CcpSession.prototype.twitterRetweet = function(username, tweetId, callback)
{
    var postData =
            "<Status>\n" +
            "  <username>" + username + "</username>\n" +
            "  <tweetId>" + tweetId + "</tweetId>\n" +
            "</Status>" ;

    this.processMessage(this.restRetweetMessage, gadgets.io.MethodType.POST, callback, postData) ;
}

CcpSession.prototype.twitterFollow = function(account_user, user_to_follow, callback)
{
	var restUrl = this.restFollow + "?account_user=" + account_user + "&user_to_follow=" + user_to_follow ;
	this.processFollow(restUrl, gadgets.io.MethodType.POST, callback) ;
}

CcpSession.prototype.twitterUnfollow = function(account_user, user_to_follow, callback)
{
    var restUrl = this.restUnfollow + "?account_user=" + account_user + "&user_to_unfollow=" + user_to_follow ;
    this.processFollow(restUrl, gadgets.io.MethodType.POST, callback) ;
}

/**
 * Determine if userA s following userB
 */
CcpSession.prototype.twitterFriendshipExists = function(oauthUsername, userA, userB, callback)
{
	var restUrl = this.restFriendshipsExists + "?user_a=" + userA + "&user_b=" + userB ;
    if ( !isEmptyString(oauthUsername) )
    {
        restUrl = restUrl + "&account_user=" + oauthUsername ;
    }
    var followMessage = new TwitterMessage(this, restUrl, gadgets.io.MethodType.GET, callback) ;
    followMessage.send() ;
}

/**
 * Retrieve the user with the given screen name's profile
 */
CcpSession.prototype.twitterUsersShow = function(oauthUsername, screenName, callback)
{
    var restUrl = this.restUsersShow + "?screenName=" + screenName ;
    if ( !isEmptyString(oauthUsername) )
    {
        restUrl = restUrl + "&account_user=" + oauthUsername ;
    }
    this.processMessage(restUrl, gadgets.io.MethodType.GET, callback) ;
}

/**
 * Retrieve the given contactId and its replies 
 */
CcpSession.prototype.getConversation = function(contactId, callback)
{
    var restUrl = this.restGetConversation + "/" + contactId ;
    this.makeRequest(restUrl, gadgets.io.MethodType.GET, callback) ;
}

/**
 * Submit an asynchronous request to a URL with the given HTTP method, 
 * passing the given post data. The response is passed to the callback function.
 */
CcpSession.prototype.makeRequest = function(url, method, callback, postdata)
{
    var params = {};
    params[gadgets.io.RequestParameters.CONTENT_TYPE] = gadgets.io.ContentType.DOM;
    params[gadgets.io.RequestParameters.METHOD] = method;
    params[gadgets.io.RequestParameters.REFRESH_INTERVAL ] = 0;

    switch (method)
    {
    case gadgets.io.MethodType.DELETE:
        break;
    case gadgets.io.MethodType.POST:
    case gadgets.io.MethodType.PUT:
        params[gadgets.io.RequestParameters.POST_DATA] = postdata;
        params[gadgets.io.RequestParameters.HEADERS] = {"Content-Type" : "application/xml;charset=UTF-8"};        
        break;
    case gadgets.io.MethodType.GET:
        params[gadgets.io.RequestParameters.HEADERS] = {"Cache-Control" : "no-cache"};
        var timeparam = { time : (new Date()).getTime() };
        if(url.indexOf("?") > 0)
        	url = url + "&" + gadgets.io.encodeValues(timeparam);
        else
        	url = url + "?" + gadgets.io.encodeValues(timeparam);     
        if (postdata != null)
            url = url + "&" + gadgets.io.encodeValues(postdata);
        break;
    }
    
    var authHeader = "Basic " + this.authString ;
    if ( params[gadgets.io.RequestParameters.HEADERS] == null )
    {
        params[gadgets.io.RequestParameters.HEADERS] = { "Authorization" :  authHeader };
    }
    else
    {
        var headers = params[gadgets.io.RequestParameters.HEADERS];
        headers["Authorization"] = authHeader;
    }
    
	gadgets.io.makeRequest(url, callback, params);
}

/**
 * Make multipe REST requests. Do not return until all requests have received
 * a response.
 */
CcpSession.prototype.makeMultipleGetRequests = function(urls, callback)
{
    var responses = new Array(urls.length) ;
    
    var i = 0 ;
    for ( i = 0 ; i < urls.length ; i++ )
    {
        var responseIndex = 0 ;
        var singleCallback = function singleCallback(response)
        {
            responses[responseIndex] = response ;
            responseIndex++ ;
            
            var receivedAll = true ;
            for ( var j = 0 ; j < responses.length ; j++ )
            {
                if ( responses[j] == undefined )
                {
                    receivedAll = false ;
                    break ;
                }
            }
            
            if ( receivedAll )
            {
                callback(responses) ;
            }
        }
        this.makeRequest(urls[i], gadgets.io.MethodType.GET, singleCallback) ;
    }
}

/**
* Hide the reply and set the social contact's state to nextState.
*/
CcpSession.prototype.closeTemplate = function(nextState)
{
	var message = "clearError" ;
	this.postMessage(message) ;
	
	message = "close:" + nextState ;
	this.postMessage(message) ;
}

/**
 * Set the heading for the reply template
 */
CcpSession.prototype.setHeading = function(heading)
{
	var message = "heading:" + heading ;
	this.postMessage(message) ;
}

/**
 * Display the given error
 */
CcpSession.prototype.showError = function(text)
{
	var message = "showError:" + text ;
	this.postMessage(message) ;
}

/**
* Clear errors using the CCP infrastructure
*/
CcpSession.prototype.clearError = function()
{
	this.postMessage("clearError") ;
}

/**
 * Post a message to the parent window.
 */
CcpSession.prototype.postMessage = function(message)
{
    log("Sending " + message) ;
	window.parent.window.parent.postMessage(message, this.origin) ;
}
	

//
// The following class stores information for a given social contact
//

function SocialContact(ccpSession, contactXml)
{
    this.ccpSession = ccpSession ;
    
    this.author      = getElementValue(contactXml, "author") ;
    this.title       = getElementValue(contactXml, "title") ;
    this.description = getElementValue(contactXml, "description") ;
    this.link        = getElementValue(contactXml, "link") ;
    this.refUrl      = getElementValue(contactXml, "refURL") ;
    
    this.isDM = false ;
    
    // Get the ID of the tweet or direct message
    //
    this.tweetId = null ;
    if ( this.link.indexOf("id=") >= 0 )
    {
        this.isDM = true ;
        this.tweetId = this.link.substring(this.link.lastIndexOf("=") + 1) ;
    }
    else
    {
        this.tweetId = this.link.substring(this.link.lastIndexOf("/") + 1) ;
    }
}
   

//
// The following class manages the author of the reserved contact's profile information
//

/**
 * Class used to manage profile information
 */
function Profile(ccpSession, nameId, imageId, descriptionId, urlId, followerCountId, followingAgentId)
{
    this.ccpSession = ccpSession ;

    this.prefs = ccpSession.prefs ;
        
    this.name = document.getElementById(nameId) ;
    
    this.image = document.getElementById(imageId) ;
    
    this.description = document.getElementById(descriptionId) ;
    
    this.url = document.getElementById(urlId) ;
    
    this.followerCount = document.getElementById(followerCountId) ;
    
    this.followingAgent = document.getElementById(followingAgentId) ;
    
    this.followingAgentMap = [] ;
}

/**
 * Populate the reserved contact's author's Twitter profile information
 */
Profile.prototype.populate = function(author, selectedAccount, oauthAccount)
{
    this.author = author ;
    
    if ( (this.author == null) || (this.author.length == 0) )
    {
        return ;
    }
    
    var profile = this ;
    
    var usersShowCallback = function(response)
    {
        if ( handleRateLimit(response, oauthAccount) )
        {
            return ;
        }
            
        var error = getErrorDetails(response) ;
        if ( error != null )
        {
            var errorMessage =
                profile.prefs.getMsg('twitter_reply_get_profile_failed') + " " + author + "<br>" +
                error ;
                
            showError(errorMessage) ;
            
            return ;
        }
            
        var profileImageUrl = getElementValue(response.data, "profileImageUrl") ;
        if ( profileImageUrl != null )
        { 
            profile.image.src = profileImageUrl ;
        }
        
        var name = getElementValue(response.data, "name") ;
        if ( name != null )
        {
            profile.name.innerHTML = name ;
        }
        
        var description = getElementValue(response.data, "description") ;
        if ( isEmptyString(description) )
        {
            description = "" ;
        }
        profile.description.innerHTML = description ;
        
        var followerCount = getElementValue(response.data, "followersCount") ;
        if ( !isEmptyString(followerCount) )
        {
            profile.followerCount.innerHTML = followerCount + " " + profile.prefs.getMsg('twitter_reply_followers') ;
        }
        
        var screenName = getElementValue(response.data, "screenName") ;
        var url = getElementValue(response.data, "url") ;
        if ( isEmptyString(url) )
        {
            url = "http://twitter.com/" + screenName ;
        }
        profile.url.href = url ;
        profile.url.innerHTML = url ;
        
        profile.updateFollowing(selectedAccount) ;
    }
    ccpSession.twitterUsersShow(oauthAccount, this.author, usersShowCallback) ;
}

/**
 * Update the UI based on whether or not the author of the reserved contact is
 * following the given agent
 */
Profile.prototype.updateFollowingUI = function(agent)
{
    var following = this.followingAgentMap[agent] ;
    if ( (following == null) || (following == undefined) )
    {
        following = false ;
    }
    
    if ( following == true )
    {
        this.followingAgent.innerHTML = this.prefs.getMsg('twitter_reply_following') + " " + agent ;
    }
    else
    {
        this.followingAgent.innerHTML = this.prefs.getMsg('twitter_reply_not_following') + " " + agent ;
    }
}

/**
 * Update whether or not the author of the reserved contact is following the given
 * agent
 */
Profile.prototype.updateFollowing = function(agent)
{
    if ( agent == null )
    {
        this.followingAgent.innerHTML = "" ;
        
        return ;
    }
    
    var state = this.followingAgentMap[agent] ;
    if ( (state != null) && (state != undefined) )
    {
        this.updateFollowingUI(agent, state) ;
        
        return ;
    }
    
    var profile = this ;
    var agentFriendshipsExistsCallback = function(response)
    {            
        profile.followingAgentMap[agent] = null ;

        if ( !handleRateLimit(response, agent) && (response.rc == 200) )
        {
            var progress = getElementValue(response.data, PROGRESS_TAG) ;
            if ( progress != TWITTER_PROGRESS_FAILED )
            {
                var friends = getElementValue(response.data, "friends") ;
                if ( friends != null )
                {
                    if ( friends == "true" )
                    {
                        profile.followingAgentMap[agent] = true ;
                    }
                    else
                    {
                        profile.followingAgentMap[agent] = false ;
                    }
                }   
            }
        }
            
        profile.updateFollowingUI(agent) ;
    }
    ccpSession.twitterFriendshipExists(agent, author, agent, agentFriendshipsExistsCallback) ;
}
   

//
// The following class manages the conversation list in the reply template.
//

var CONTACT_AUTHOR_PREFIX      = "contactAuthor_" ;
var CONTACT_LINK_PREFIX        = "contactLink_" ;
var CONTACT_DESCRIPTION_PREFIX = "contactDescription_" ;
var RETWEET_ACTION_PREFIX      = "retweetAction_" ;
var REPLY_ACTION_PREFIX        = "replyAction_" ;
var DM_ACTION_PREFIX           = "directMessage_" ;


/**
 * Class used to manage the conversation displayed on the reply template.
 */
function Conversation(ccpSession, conversationDivId)
{
    this.contactId = null ;
   
    // Map the contact's reference URL to a SocialContact object.
    // 
    this.urlToContactMap = [] ;
    
    this.contactList = [] ;
    
    this.conversationDiv = document.getElementById(conversationDivId) ;
    
    this.ccpSession = ccpSession ;
    
    this.prefs = ccpSession.prefs ;
}

/**
 * Create one of the actions placed at the bottom of each conversation entry
 */
Conversation.prototype.createAction = function(id, name)
{
    var action = document.createElement("a") ;
    action.setAttribute("id", id) ;
    action.setAttribute("class", "replyAction") ;
    action.innerHTML = name ;
    
    return action ;
}

/**
 * Populate the conversation div
 */
Conversation.prototype.populate = function(contactId, account)
{
    this.contactId = contactId ;
    
    var conversation = this ;
    
    var conversationCallback = function(response)
    {
        if ( response.rc != 200 )
        {
            showError(
                conversation.prefs.getMsg('twitter_reply_get_conversation_failed') + "<br>" +
                conversation.prefs.getMsg('twitter_reply_error_code') + " " + response.rc + "<br>" +
                conversation.prefs.getMsg('twitter_reply_error_message') + " " + response.text) ;
        
            return ;
        }
        
        var contacts = response.data.getElementsByTagName("SocialContact") ;
        var i = 0 ;
        for ( i = 0 ; i < contacts.length ; i++ )
        {
            var contact = new SocialContact(ccpSession, contacts[i]) ;
    
            var contactId = escape(contact.refUrl) ;
            conversation.urlToContactMap[contactId] = contact ;
            conversation.contactList[i] = contact ;
            
            var authorDiv = document.createElement("div") ;
            authorDiv.className = "author" ;
            authorDiv.innerHTML = contact.author ;
            authorDiv.setAttribute("id", CONTACT_AUTHOR_PREFIX + contactId) ;
            var titleDiv = document.createElement("div") ;
            titleDiv.className = "summary" ;
            
            var linkElement = document.createElement("a") ;
            linkElement.target = "_blank" ;
            linkElement.href = contact.link ;
            linkElement.innerHTML = contact.title ;
            linkElement.setAttribute("id", CONTACT_LINK_PREFIX + contactId) ;
            titleDiv.appendChild(linkElement) ;
            
            var descriptionDiv = document.createElement("div") ;
            descriptionDiv.innerHTML = contact.description ;
            descriptionDiv.setAttribute("id", CONTACT_DESCRIPTION_PREFIX + contactId) ;
            
            conversation.conversationDiv.appendChild(authorDiv) ;
            conversation.conversationDiv.appendChild(titleDiv) ;
            conversation.conversationDiv.appendChild(descriptionDiv) ;
            
            var actionDiv = document.createElement("div") ;
            actionDiv.setAttribute("class", "actionGroup") ;
            
            var escContactRef = escape(contact.refUrl) ;
            
            var replyActionId = REPLY_ACTION_PREFIX + escContactRef ;
            replyAction = conversation.createAction(replyActionId, conversation.prefs.getMsg('twitter_reply_reply_action')) ;
            replyAction.setAttribute("onclick", "showReplyDialog('" + escContactRef + "')") ;            
            actionDiv.appendChild(replyAction) ;
            
            if ( !contact.isDM )
            {
                var retweetActionId = RETWEET_ACTION_PREFIX + escContactRef ;
                retweetAction = conversation.createAction(retweetActionId, conversation.prefs.getMsg('twitter_reply_retweet_action')) ;
                retweetAction.setAttribute("onclick", "showRetweetDialog('" + escContactRef + "')") ;
                actionDiv.appendChild(retweetAction) ;
            }
            
            var dmActionId = DM_ACTION_PREFIX + escContactRef ;
            directMessageAction = conversation.createAction(dmActionId, conversation.prefs.getMsg('twitter_reply_dm_action')) ;
            directMessageAction.setAttribute("onclick", "showDirectMessageDialog('" + escContactRef + "')") ;
            
            actionDiv.appendChild(directMessageAction) ;
                
            conversation.conversationDiv.appendChild(actionDiv) ;
                    
            conversation.conversationDiv.style.overflow = "auto" ;
            
            conversation.updateActions(account) ;
        }
    }            
    this.ccpSession.getConversation(this.contactId, conversationCallback) ;
}

/**
 * This method is used to notify the conversation object that the account selected
 * on the reply template has changed.
 */
Conversation.prototype.updateActions = function(account)
{
    var visibility = "visible" ;
    if ( account == null )
    {
        visibility = "hidden" ;
    }

    this.setVisibility(visibility) ;    
}

/**
 * Hide the actions displayed in the conversation list
 */
Conversation.prototype.disable = function()
{
    this.setVisibility("hidden") ;
}

/**
 * Show the actions displayed in the conversation list
 */
Conversation.prototype.enable = function()
{
    this.setVisibility("visible") ;
}

/**
 * Set the visibility of the actions displayed in the conversation list
 */
Conversation.prototype.setVisibility = function(visibility)
{
    var i = 0 ;
    for ( i = 0 ; i < this.contactList.length ; i++ )
    {
        var contact = this.contactList[i] ;
        
        var escContactRef = escape(contact.refUrl) ;
        
        var retweetActionId = RETWEET_ACTION_PREFIX + escContactRef ;
        var action = document.getElementById(retweetActionId) ;
        if ( action != null )
        {
            action.style.visibility = visibility ;
        }
        
        var replyActionId = REPLY_ACTION_PREFIX + escContactRef ;
        action = document.getElementById(replyActionId) ;
        if ( action != null )
        {
            action.style.visibility = visibility ;
        }
        
        var dmActionId = DM_ACTION_PREFIX + escContactRef ;
        action = document.getElementById(dmActionId) ;
        if ( action != null )
        {
            action.style.visibility = visibility ;
        }
    }
}

   

//
// The following class manages the agent account selector and follow button on the reply template
//

/**
 * Class used to manage agent account-related UI.
 */
function Agent(prefs, followButtonId, followAuthorId, agentSelectId)
{
    this.author = null ;
    
    this.followButton = document.getElementById(followButtonId) ;
    this.followAuthor = document.getElementById(followAuthorId) ;
    this.agentSelect  = document.getElementById(agentSelectId) ;
    
    this.followingAuthorMap = [] ;
    
    this.prefs = prefs ;
}

/**
 * Set the author of the reserved contact
 */
Agent.prototype.setAuthor = function(author)
{
    this.author = author ;
    
    if ( this.author != null )
    {
        this.followAuthor.innerHTML = this.author ;
    }
}

/**
 * Update the follow button based on whether the currently selected agent is
 * following the author of the reserved contact.
 */
Agent.prototype.updateFollowingUI = function(agent)
{
    var following = this.followingAuthorMap[agent] ;
    if ( (following == null) || (following == undefined) )
    {
        this.followButton.disabled = true ;
        
        return ;
    }

    this.followButton.disabled = false ;
    if ( following == false )
    {
        this.followButton.value = this.prefs.getMsg('twitter_reply_follow') ;
        this.followButton.disabled = false ;
        this.followButton.onclick = follow ;
    }
    else
    {
        this.followButton.value = this.prefs.getMsg('twitter_reply_unfollow') ;
        this.followButton.disabled = false ;
        this.followButton.onclick = unfollow ;
    }
}

/**
 * Determine if the given agent is following the author of the reserved contact.
 */
Agent.prototype.updateFollowing = function(newAgent)
{
    if ( (this.author == null) || (newAgent == null) || (newAgent == this.author) )
    {
        this.followButton.disabled = true ;
        
        return ;
    }
    
    var following = this.followingAuthorMap[newAgent] ;
    if ( (following != null) && (following != undefined) )
    {
        this.updateFollowingUI(newAgent) ;
        
        return ;
    }
    
    followButton.disabled = true ;
    
    var agent = this ;
    var authorFriendshipsExistsCallback = function(response)
    {
        agent.followingAuthorMap[newAgent] = null ;

        if ( !handleRateLimit(response, newAgent) && (response.rc == 200) )
        {
            var progress = getElementValue(response.data, PROGRESS_TAG) ;
            if ( progress != TWITTER_PROGRESS_FAILED )
            {
                var friends = getElementValue(response.data, "friends") ;
                if ( friends != null )
                {
                    if ( friends == "true" )
                    {
                        agent.followingAuthorMap[newAgent] = true ;
                    }
                    else
                    {
                        agent.followingAuthorMap[newAgent] = false ;
                    }
                }   
            }
        }
            
        agent.updateFollowingUI(newAgent) ;
    }
    ccpSession.twitterFriendshipExists(newAgent, newAgent, this.author, authorFriendshipsExistsCallback) ;
}

/**
 * The specified agent will follow the given author.
 */
Agent.prototype.follow = function(selectedAgent, author)
{
    if ( (selectedAgent == null) || (author == null) )
    {
        return ;
    }
    
    if ( this.followButton.disabled )
    {
        return ;
    }
    
    this.followButton.disabled = true ;
    this.agentSelect.disabled = true ;
    
    var agent = this ;
    
    var followCallback = function(response)
    {
        agent.followButton.disabled = false ;
        agent.agentSelect.disabled = false ;
    
        var error = getErrorDetails(response) ;
        if ( error != null )
        {
            var errorMessage =
                agent.prefs.getMsg('twitter_reply_follow_failed') + " " + author + " " + agent.prefs.getMsg('twitter_reply_using') + " " + selectedAgent + "<br>" +
                error ;
            showError(errorMessage) ;

            return ;                
        }
        
        agent.followingAuthorMap[selectedAgent] = true ;
        agent.updateFollowingUI(selectedAgent) ;
    }
    ccpSession.twitterFollow(selectedAgent, author, followCallback) ;
}

/**
 * The specified agent will no longer follow the given author.
 */
Agent.prototype.unfollow = function(selectedAgent, author)
{
    if ( this.followButton.disabled )
    {
        return ;
    }
    
    this.followButton.disabled = true ;
    this.agentSelect.disabled = true ;

    var agent = this ;
    
    var unfollowCallback = function(response)
    {
        agent.followButton.disabled = false ;
        agent.agentSelect.disabled = false ;
        
        var error = getErrorDetails(response) ;
        if ( error != null )
        {
            var errorMessage =
                agent.prefs.getMsg('twitter_reply_unfollow_failed') + " " + author + " " + agent.prefs.getMsg('twitter_reply_using') + " " + selectedAgent + "<br>" +
                error ;
            showError(errorMessage) ;

            return ;                
        }
        
        agent.followingAuthorMap[selectedAgent] = false ;
        agent.updateFollowingUI(selectedAgent) ;
    }
    ccpSession.twitterUnfollow(selectedAgent, author, unfollowCallback) ;
}

/**
 * Disabled the follow button
 */
Agent.prototype.disable = function()
{
    this.followButton.disabled = true ;
}

/**
 * Enable the follow button
 */
Agent.prototype.enable = function()
{
    this.followButton.enabled = true ;
}
   


//
// Constants
//

// Type value of a CCP Twitter Account feed
// 
var TWITTER_ACOUNT_TYPE = 6 ;

// Maximum number of characters in a tweet
//
var MAX_TWEET_LEN = 140 ;

var DIRECT_MESSAGE_PREFIX = "Direct message:" ;

var ACCOUNT_NAME_KEY = "accountName" ;


// File-Scope Variables
//
var ccpSession   = null ;
var conversation = null ;
var profile      = null ;
var agent        = null ;

var author = null ;
var timestamp = null ;
var contactId = null ;


// References to UI elements
//
var followButton = null ;
var accounts     = null ;


/**
* Hide the reply and set the social contact's state to nextState.
*/
function closeTemplate(nextState)
{
    ccpSession.closeTemplate(nextState) ;
}

/**
 * Set the heading for the reply template
 */
function setHeading(heading)
{
    ccpSession.setHeading(heading) ;
}

/**
* Show an error using the CCP infrastructure
*/
function showError(message)
{
    ccpSession.showError(message) ;
}

/**
* Clear errors using the CCP infrastructure
*/
function clearError()
{
    ccpSession.clearError() ;
}

/**
 * Return the value for the given key stored in the cookie
 */
function getFromCookie(key)
{
	var keyEquals = key + "=" ;
	var cookies = document.cookie.split(';') ;
	for ( var i = 0 ; i < cookies.length ; i++ )
	{
		var cookie = cookies[i] ;
		while ( cookie.charAt(0) == ' ')
		{
			cookie = cookie.substring(1, cookie.length) ;
		}
		
		if ( cookie.indexOf(keyEquals) == 0 )
		{
			return cookie.substring(keyEquals.length, cookie.length) ;
		}
	}
	
	return null ;
}

/**
 * Trim excess content from the author's name. An author of a Twitter contact
 * should not contain spaces.
 */
function trimAuthor(author)
{
    if ( author != null )
    {
        var space = author.indexOf(' ') ;
        if ( space != -1 )
        {
            author = author.substring(0, space) ;
        }
    }

    return author ;
}        

/*
 * This function parses the date and formats it so that it works for IE
 * Twitter sends a weird date String like "Thu Feb 17 23:18:36 +0000 2011"
 * wherein the year is after the timezone. So rearraging and some tweaks to timezone makes it work for all browsers
 * The rearranged dateString looks like "Thu Feb 17 2011 23:18:36 UTC"
 */
function fixDateFormat(dateString) 
{
  var p = dateString.split(' ');
  return new Date(Date.parse(p[1]+" "+p[2]+", "+p[5]+" "+p[3]+" UTC"));
} 

/*
 * Returns a formatted time for the given date string in the format "Thu Feb 17 23:18:36 +0000 2011"
 */
function formattedDate(dateString)
{
    var date = fixDateFormat(dateString);
    var hours = date.getHours();
    var minutes = date.getMinutes();
    var amPM = (hours > 11)? "__MSG_twitter_reply_pm__": "__MSG_twitter_reply_am__";
    if ( hours != 12 )
    {
        hours = hours % 12;
    }
    minutes = (minutes < 10)? "0"+minutes : minutes;
    hours = (hours < 10)? "0"+hours : hours;
    var result = hours + ":" + minutes + " " + amPM;
    return result;
}

/**
 * Check to see if the given response indicates that the account has been
 * rate-limited by Twitter.  If the account has been rate-limited, disable
 * the UI and display an error message.  Otherwise, enable the UI.
 */
var rateLimited = false ;

/**
 * Check the response to a reply API message to see if Twitter is rate limited
 * the given account or the system.
 *
 * If twitterAccount is null, a message will be displayed stating the system is
 * rate limited. Otherwise, a message stating the account is rate limitied will
 * be displayed.
 */
function handleRateLimit(responseObj, twitterAccount)
{
    var wasRateLimited = rateLimited ;
    
    rateLimited = getElementValue(responseObj.data, RATE_LIMITED_TAG) == "true" ;
    if ( !rateLimited )
    {
        if ( wasRateLimited )
        {            
            clearError() ;
            disableUI(false) ;
        }
        
        return false ;
    }

    if ( !wasRateLimited )
    {
        disableUI(true) ;
            
        var rateLimitEndDate = getElementValue(responseObj.data, HTTP_RESPONSE_MSG_TAG) ;
        log("End date: " + rateLimitEndDate) ;
        
        var errorMsg = "" ;
        if ( (twitterAccount == null) )
        {
            errorMsg = "__MSG_twitter_reply_system_rate_limited__" ;
            errorMsg = errorMsg + "<br>__MSG_twitter_reply_system_rate_limited_until__ " + formattedDate(rateLimitEndDate) ;
        }
        else
        {
            errorMsg = "__MSG_twitter_reply_account_rate_limited__ " + twitterAccount ;
            errorMsg = errorMsg + "<br>__MSG_twitter_reply_account_rate_limited_until__ " + formattedDate(rateLimitEndDate) ;
        }
        showError(errorMsg) ;
    }
    
    return true ;
}

/**
 * Get the erorr-related details of a response to a reply API message.
 * Null is returned if the operation was successful.
 */
function getErrorDetails(response)
{
    if ( response.rc != 200 )
    {
        return "__MSG_twitter_reply_error__ " + response.rc ;
    }

    var progress = getElementValue(response.data, PROGRESS_TAG) ;
    if ( progress == TWITTER_PROGRESS_FAILED )
    {
        var error =
            "__MSG_twitter_reply_twitter_error__ " + getElementValue(response.data, "httpResponseCode") + "<br>" +
            "__MSG_twitter_reply_twitter_message__ " + getElementValue(response.data, "httpResponseMessage") ;
            
        return error ;
    }
    
    return null ;
}

/**
 * Disable the reply template UI. This is done when the account is rate-limited.
 */
function disableUI(disabled)
{
    if ( disabled )
    {
        agent.disable() ;
        conversation.disable() ;
    }
    else
    {
        clearError() ;
        
        agent.enable() ;
        conversation.enable() ;
    }    
}

/**
 * Set the given key/value pair in the cookie
 */
function setInCookie(key, value)
{
	var curDate = new Date() ;
	
	// Expire in 30 days
	//
	var expiresDate = new Date(curDate.getTime() + (1000 * 60 * 60 * 24 * 30)) ;
	document.cookie = key + "=" + value + "; expires=" + expiresDate.toGMTString() + "; path=/" ;
}

/**
 * Show the given progress message
 */
function showProgressMessage(message)
{
    var progressDiv = document.getElementById("progress") ;
    progressDiv.style.height = this.innerHeight + "px" ;
    progressDiv.style.width = this.innerWidth + "px" ;
    
    var messageSpan = document.getElementById("progressSpan") ;
    messageSpan.innerHTML = message ;

    var border = document.getElementById("progressMessage") ;
    
    border.style.top = (this.innerHeight / 2) - (border.offsetHeight / 2) + "px" ;
    border.style.left = (this.innerWidth / 2) - (border.offsetWidth / 2) + "px" ;
    
    progressDiv.style.visibility = "visible" ;  
}

/**
 * Hide the progress message
 */
function hideProgressMessage()
{
    var progressDiv = document.getElementById("progress") ;
    progressDiv.style.visibility = "hidden" ;  
}

/**
 * Send a reply using the selectedAccount.  The text in the reply area is used
 * as the text of the message.
 */
function retweet(tweetId)
{
    var selectedAccount = accounts.options[accounts.selectedIndex].value ;
    
    showProgressMessage("__MSG_twitter_reply_retweet_progress__") ;
    
    var retweetCallback = function(response)
    {
        hideProgressMessage() ;
        
        var error = getErrorDetails(response) ;
        if ( error != null )
        {
            var errorMessage = "__MSG_twitter_reply_retweet_failed__ " + selectedAccount + "<br>" + error ;
            showError(errorMessage) ;
            
            return ;
        }

        setInCookie(ACCOUNT_NAME_KEY, selectedAccount) ;

        closeTemplate(SC_STATUS_HANDLED) ;
    }
    ccpSession.twitterRetweet(selectedAccount, tweetId, retweetCallback) ;
}

/**
 * Retweet the tweet with the given ID
 */
function sendRetweet(tweetId)
{    
    closeDialog() ;

    showProgressMessage("__MSG_twitter_reply_retweet_progress__") ;
    
    retweet(tweetId) ;
}

/**
 * Display the social contact with the given ID in the retweet dialog
 */
function showRetweetDialog(contactId)
{
    setDraggableDialog("draggableDialogHeader", "retweetDialog") ;
    
    var contact = conversation.urlToContactMap[contactId] ;
    
    document.getElementById("retweetDialog_header").innerHTML = "__MSG_twitter_reply_retweet_title__" ;
    document.getElementById("retweetDialog_author").innerHTML = contact.author ;
    
    if ( isEmptyString(contact.description) )
    {
        document.getElementById("retweetDialog_description").innerHTML = contact.title ;
    }
    else
    {
        document.getElementById("retweetDialog_description").innerHTML = contact.description ;
    }
    
    document.getElementById("retweetDialog_sendButton").setAttribute("onclick", "sendRetweet('" + contact.tweetId + "')") ;
    
    openDialog() ;
}

/**
 * Send a reply using the selectedAccount.  The text in the reply area is used
 * as the text of the message.
 */
function reply(selectedAccount, message, tweetId)
{
    var replyCallback = function(response)
	{
	    hideProgressMessage() ;

        var error = getErrorDetails(response) ; 
        if ( error != null )
        {
            var errorMessage = "__MSG_twitter_reply_reply_failed__ " + selectedAccount + "<br>" + error ;
            showError(errorMessage) ;
            
            return ;
        }

		setInCookie(ACCOUNT_NAME_KEY, selectedAccount) ;

		closeTemplate(SC_STATUS_HANDLED) ;
	}
	ccpSession.twitterReply(selectedAccount, message, tweetId, replyCallback) ;
}

/**
 * Reply to the given tweet
 */
function sendReply(tweetId)
{    
    closeDialog() ;

    showProgressMessage("__MSG_twitter_reply_reply_progress__") ;
    
    var selectedAccount = accounts.options[accounts.selectedIndex].value ;
    
    reply(selectedAccount, document.getElementById("replyDialog_text").value, tweetId) ;
}

/**
 * Display the reply dialog with the social contact with the specified ID
 */
function showReplyDialog(contactId)
{
    setDraggableDialog("draggableDialogHeader", "replyDialog") ;
    
    var contact = conversation.urlToContactMap[contactId] ;
    
    var contactAuthor = trimAuthor(contact.author) ;
    
    var replyPrefix = "@" + contactAuthor ;
    document.getElementById("replyDialog_header").innerHTML = "__MSG_twitter_reply_reply_title__ " + replyPrefix ;
    document.getElementById("replyDialog_text").value = replyPrefix + " " ;
    document.getElementById("replyDialog_author").innerHTML = contactAuthor ;
    
    if ( isEmptyString(contact.description) )
    {
        document.getElementById("replyDialog_description").innerHTML = contact.title ;
    }
    else
    {
        document.getElementById("replyDialog_description").innerHTML = contact.description ;
    }
    
    document.getElementById("replyDialog_sendButton").setAttribute("onclick", "sendReply('" + contact.tweetId + "')") ;
    updateCharactersLeft("replyDialog_text", "replyDialog_charactersLeft", "replyDialog_sendButton") ;
    
    openDialog() ;
}

/**
 * Send a direct message using the selectedAccount.  The author of the social
 * contact is the target of the direct message.  The text in the reply area is
 * used as the text of the message.
 */
function directMessage(selectedAccount, contactAuthor, message)
{
	var directMessageCallback = function(response)
	{
        hideProgressMessage() ;
        
        var error = getErrorDetails(response) ; 
        if ( error != null )
        {
            var errorMessage = "__MSG_twitter_reply_dm_failed__ " + selectedAccount + "<br>" + error ;
            showError(errorMessage) ;
            
            return ;
        }

		setInCookie(ACCOUNT_NAME_KEY, selectedAccount) ;

        closeTemplate(SC_STATUS_HANDLED) ;
	}
	ccpSession.twitterDirectMessage(selectedAccount, contactAuthor, message, directMessageCallback) ;
}

/**
 * Send a direct message to the specified author
 */
function sendDirectMessage(contactAuthor)
{    
    closeDialog() ;

    showProgressMessage("__MSG_twitter_reply_dm_progress__") ;
    
    var selectedAccount = accounts.options[accounts.selectedIndex].value ;
    
    contactAuthor = trimAuthor(contactAuthor) ;
    
    directMessage(selectedAccount, contactAuthor, document.getElementById("dmDialog_text").value) ;
}

/**
 * Show the direct message dialog based on the social contact with the given ID
 */
function showDirectMessageDialog(contactId)
{
    setDraggableDialog("draggableDialogHeader", "dmDialog") ;
    
    var contact = conversation.urlToContactMap[contactId] ;
    
    document.getElementById("dmDialog_header").innerHTML = "__MSG_twitter_reply_dm_title__ " + contact.author ;
    document.getElementById("dmDialog_text").value = "" ;
    document.getElementById("dmDialog_sendButton").setAttribute("onclick", "sendDirectMessage('" + contact.author + "')") ;
    updateCharactersLeft("dmDialog_text", "dmDialog_charactersLeft", "dmDialog_sendButton") ;
    
    openDialog() ;
}

/**
 * Make sure the text in the reply area is within Twitter's limits.
 */
function updateCharactersLeft(textAreaId, charsLeftId, sendButtonId)
{
    var textLength = document.getElementById(textAreaId).value.length ;
    if ( (textLength <= 0) || (textLength > MAX_TWEET_LEN) )
    {
        document.getElementById(sendButtonId).disabled = true ;
    }
    else
    {
        document.getElementById(sendButtonId).disabled = false ;
    }
    
    var charsLeft = MAX_TWEET_LEN - document.getElementById(textAreaId).value.length ;
	document.getElementById(charsLeftId).innerHTML = charsLeft ;
}

/**
 * Get the currently selected account
 */
function getSelectedAccount()
{
    var account = null ;
    if ( accounts.selectedIndex > 0 )
    {
        account = accounts.options[accounts.selectedIndex].value ;
    }
    
    return account ;
}

/**
 * HTML UI callbacks
 */
 
/**
 * Process changes to the account pulldown
 */
function accountChanged()
{
    var account = getSelectedAccount() ;    
    if ( account != null )
    {
        setInCookie(ACCOUNT_NAME_KEY, account) ;
    }
    
	conversation.updateActions(account) ;
	profile.updateFollowing(account) ;
	agent.updateFollowing(account) ;
}

/**
 * Follow the author of the social contact
 */
function follow()
{
	if ( accounts.selectedIndex == 0 )
	{
		return ;
	}
	
	agent.follow(accounts.options[accounts.selectedIndex].value, author) ;
}

/**
 * Unfollow the author of the social contact
 */
function unfollow()
{
    if ( accounts.selectedIndex == 0 )
    {
        return ;
    }
    
    agent.unfollow(accounts.options[accounts.selectedIndex].value, author) ;
}

/**
 * Store the details of the given social contact response
 */
function updateWithSocialContact(response)
{
    var contact = response.data ;
    author = getElementValue(contact, "author") ;
    author = trimAuthor(author) ;
        
    if ( (author == null) || (author.length == 0) )
    {
        followButton.style.visibility = "hidden" ;
    }
        
    contactId = getElementValue(contact, "id") ;
        
    timestamp = getElementValue(contact, "statusTimestamp") ;
}

/**
 * Update the UI (mainly the account selector) with the given list of accounts
 */
function updateWithAccounts(response)
{
    var feeds = response.data.getElementsByTagName("Feed") ;
    if ( feeds == null )
    {
        return ;
    }
            
    var ccpAccounts = [] ;
    for ( var i = 0 ; i < feeds.length ; i++ )
    {
        var feedType = feeds[i].getElementsByTagName("type")[0].firstChild.nodeValue ;
                    
        if ( feedType == TWITTER_ACOUNT_TYPE )
        {
            ccpAccounts[ccpAccounts.length] =
                feeds[i].getElementsByTagName("authenticationUsername")[0].firstChild.nodeValue ;
        }
    }
            
    var selectedAccount = getFromCookie(ACCOUNT_NAME_KEY) ;
    accounts[accounts.length] = new Option("", "") ;
            
    for ( var i = 0 ; i < ccpAccounts.length ; i++ )
    {
        accounts[accounts.length] = new Option(ccpAccounts[i], ccpAccounts[i]) ;
        if ( ccpAccounts[i] == selectedAccount )
        {
            accounts.selectedIndex = accounts.length - 1 ;
        }
    }
            
    accounts.disabled = false ;
}

/**
 * onLoad() entry point into the reply template
 */
function main()
{
    followButton   = document.getElementById("followButton") ;
    accounts       = document.getElementById("accounts") ;
    
    ccpSession = new CcpSession(window.location.href) ;
    conversation = new Conversation(ccpSession, "conversation") ;
    profile = new Profile(ccpSession,
                    "profileName", "profileImage", "profileDescription",
                    "profileUrl", "profileFollowersCount", "profileFollowingAgent") ;
    agent = new Agent(ccpSession.prefs, "followButton", "followAuthor", "accounts") ;
    
    setHeading("Twitter Reply") ;

    var urls = [] ;
    urls[0] = ccpSession.restSocialContact ;
    urls[1] = ccpSession.restGetFeedList ;
    
    var contactCallback = function(response)
    {
        if ( response.rc != 200 )
        {
            showError(
                "__MSG_twitter_reply_get_contact_failed__<br>" +
                "__MSG_twitter_reply_error_code__ " + response.rc + "<br>" +
                "__MSG_twitter_reply_error_message__ " + response.text) ;
        
            return ;
        }
        
        updateWithSocialContact(response) ;

        var feedsCallback = function(response)
        {
            if ( response.rc != 200 )
            {
                showError(
                    "__MSG_twitter_reply_get_accounts_failed__<br>" +
                    "__MSG_twitter_reply_error_code__ " + response.rc + "<br>" +
                    "__MSG_twitter_reply_error_message__ " + response.text) ;
                
                return ;
            }
            
            updateWithAccounts(response) ;
            
            var account = getSelectedAccount() ;
            var oauthAccount = account ;
            if ( (oauthAccount == null) && (accounts.length > 1) )
            {
                oauthAccount = accounts[1].value ; 
            }
            conversation.populate(contactId, account) ;
            profile.populate(author, account, oauthAccount) ;
            agent.setAuthor(author) ;
            agent.updateFollowing(account) ;
        }        
        ccpSession.getAllCcpFeeds(feedsCallback) ;
    }
    ccpSession.getSocialContact(contactCallback) ;
}

</script>

</head>

<body onLoad="main()">
<div id="reply"  style="width:50%">
  <!-- Profile -->
  <div>
    <div><label id="profileName" class="profileName"></label></div>
  <div>
  <div class="profilePicture">
    <img id="profileImage"/>
  </div>
  <div class="profile">
    <div id="profileDescription" class="profileText"></div>
      <div class="profileUrl">
        <a id="profileUrl" target="_blank" href="javascript:void(0)">
      </div>
      <div class="profileText">
        <span id="profileFollowersCount"></span>
      </div>
      <div class="profileText">
        <span id="profileFollowingAgent"></span>
      </div>              
    </div>
  </div>
  
  <!-- Follow and account collection -->
  <div>
      <div style="padding-top: 10px;">
          <div style="float:left;">
              <label>__MSG_twitter_reply_account__&nbsp</label>
              <select id="accounts" tabindex=1 onchange="javascript:accountChanged()">
              </select>
          </div>
          <div style="float:left; margin-left:60px">
              <input id="followButton" type="button" value="__MSG_twitter_reply_follow__" disabled="true" onclick="javascript:follow()">
              <span id="followAuthor"></span>
          </div>
      </div>
  </div>  
  
  <!-- Conversation -->
  <div id="conversation" class="conversation"/></div>
  
  <!-- Reply dialog -->
  <div id="replyDialog" class="draggableDialog">
    <div id="replyDialog_header" class="draggableDialogHeader"></div>
    <div class="closeDialog">
      <b id="replyDialogClose" onclick="closeDialog()">x</b>
    </div>
    <div class="innerDialog">
      <div>
        <textarea id="replyDialog_text" class="tweetArea"
          onchange="javascript:updateCharactersLeft('replyDialog_text', 'replyDialog_charactersLeft', 'replyDialog_sendButton')"
          onkeyup="javascript:updateCharactersLeft('replyDialog_text', 'replyDialog_charactersLeft', 'replyDialog_sendButton')"
          onkeypress="javascript:updateCharactersLeft('replyDialog_text', 'replyDialog_charactersLeft', 'replyDialog_sendButton')">
        </textarea>
      </div>
      <div class="dialogButtons">
        <label id="replyDialog_charactersLeft" class="countDown">140</label>
        <input id="replyDialog_sendButton" class="tweetButton" type="button" value="__MSG_twitter_reply_tweet__">
      </div>
      <div class="repliedToTweet">
        <div id="replyDialog_author" class="authorSmall"></div>
        <div id="replyDialog_description" class="descriptionSmall"></div>
      </div>
    </div>
  </div>
  
  <!-- Retweet dialog -->
  <div id="retweetDialog" class="draggableDialog">
    <div id="retweetDialog_header" class="draggableDialogHeader"></div>
    <div class="closeDialog">
      <b id="retweetDialogClose" onclick="closeDialog()">x</b>
    </div>
    <div class="innerDialog">
      <div class="retweetedTweet">
        <div id="retweetDialog_author" class="authorSmall"></div>
        <div id="retweetDialog_description" class="descriptionSmall"></div>
      </div>
      <div class="dialogButtons">
        <input id="retweetDialog_sendButton" class="tweetButton" type="button" value="__MSG_twitter_reply_retweet__">
      </div>
    </div>
  </div>
  
  <!-- Direct message dialog -->
  <div id="dmDialog" class="draggableDialog">
    <div id="dmDialog_header" class="draggableDialogHeader"></div>
    <div class="closeDialog">
      <b id="dmDialogClose" onclick="closeDialog()">x</b>
    </div>
    <div class="innerDialog">
      <div>
        <textarea id="dmDialog_text" class="tweetArea"
          onchange="javascript:updateCharactersLeft('dmDialog_text', 'dmDialog_charactersLeft', 'dmDialog_sendButton')"
          onkeyup="javascript:updateCharactersLeft('dmDialog_text', 'dmDialog_charactersLeft', 'dmDialog_sendButton')"
          onkeypress="javascript:updateCharactersLeft('dmDialog_text', 'dmDialog_charactersLeft', 'dmDialog_sendButton')">
        </textarea>
      </div>
      <div class="dialogButtons">
        <label id="dmDialog_charactersLeft" class="countDown">140</label>
        <input id="dmDialog_sendButton" class="tweetButton" type="button" value="__MSG_twitter_reply_send__">
      </div>
    </div>
  </div>
  
  <div id="progress" class="progressLayer">
    <div id="progressMessage" class="progressMessage">
      <span id="progressSpan" class="progressSpan"></span>
    </div>
  </div>
</div>

</body>
</html>    
  ]]>
  </Content>
</Module>

